package com.taobao.api.internal.tmc;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import com.taobao.top.link.LinkException;
import com.taobao.top.link.Logger;
import com.taobao.top.link.LoggerFactory;
import com.taobao.top.link.channel.ChannelException;
import com.taobao.top.link.channel.ClientChannelSharedSelector;
import com.taobao.top.link.channel.embedded.EmbeddedClientChannelSharedSelector;
import com.taobao.top.link.endpoint.Endpoint;
import com.taobao.top.link.endpoint.EndpointChannelHandler;
import com.taobao.top.link.endpoint.EndpointProxy;
import com.taobao.top.link.endpoint.Identity;
import com.taobao.top.link.endpoint.MessageHandler;
import com.taobao.top.link.logging.LogUtil;

// poll-push mix client
class MixClient {

	protected Logger logger;
	protected Identity id;
	private Endpoint endpoint;
	private URI serverUri;
	private EndpointProxy server;

	private Timer timer;
	protected int reconnectInterval = 30000;

	public MixClient(Identity id) {
		// whatever, log first
		LoggerFactory loggerFactory = LogUtil.getLoggerFactory(this);
		this.logger = loggerFactory.create(this);

		// sharedpool with heartbeat 60s
		// ClientChannelSharedSelector selector = new
		// ClientChannelSharedSelector(loggerFactory);
		ClientChannelSharedSelector selector = new EmbeddedClientChannelSharedSelector(loggerFactory);
		selector.setHeartbeat(60000);

		// custom scheduler
		EndpointChannelHandler channelHandler = new EndpointChannelHandler(loggerFactory);
		// client do not need complex scheduler
		// channelHandler.setScheduler(scheduler);

		this.endpoint = new Endpoint(loggerFactory, this.id = id);
		this.endpoint.setClientChannelSelector(selector);
		this.endpoint.setChannelHandler(channelHandler);
	}

	public void setMessageHandler(MessageHandler handler) {
		this.endpoint.setMessageHandler(handler);
	}

	public final void connect(String uri) throws LinkException {
		try {
			this.connect(new URI(uri));
		} catch (URISyntaxException e) {
			this.logger.error(e);
		}
	}

	public final void connect(URI uri) throws LinkException {
		this.server = this.endpoint.getEndpoint(new ServerIdentity(), uri, this.createConnectHeaders());
		this.serverUri = uri;
		this.doReconnect();
		this.logger.info("connected to tmc server: %s", this.serverUri);
	}

	public void disconnect() {
	}

	public final void send(Map<String, String> message) throws ChannelException {
		this.server.send(message);
	}

	public final void sendAndWait(Map<String, String> message, int timeout) throws LinkException {
		this.server.sendAndWait(message, timeout);
	}

	protected Map<String, String> createConnectHeaders() {
		return null;
	}

	private void doReconnect() {
		this.stopReconnect();
		this.timer = new Timer();
		this.timer.schedule(new TimerTask() {
			@Override
			public void run() {
				try {
					if (server.hasValidSender())
						return;
				} catch (Exception e) {
					logger.warn(e);
				}
				try {
					logger.warn("reconnecting...");
					connect(serverUri);
				} catch (LinkException e) {
					logger.warn("reconnect error", e);
				}
			}
		}, this.reconnectInterval, this.reconnectInterval);
	}

	private void stopReconnect() {
		if (this.timer == null)
			return;
		this.timer.cancel();
	}

	public class ServerIdentity implements Identity {
		public Identity parse(Object data) throws LinkException {
			return null;
		}

		public void render(Object to) {
		}

		public boolean equals(Identity id) {
			return id instanceof ServerIdentity;
		}

		public String toString() {
			return id.toString();
		}
	}
}
